package bll

import (
	log "auth/collector/logger"
	"auth/errors"
	"auth/event"
	"auth/model"
	"auth/model/entity"
	"auth/store"
	"auth/store/postgres"
	"gorm.io/gorm"
	"time"
)

type dept struct {
	iDept store.IDept
	iUser store.IUser
}

var Dept = &dept{}

func (a *dept) init() func() {
	a.iDept = postgres.Dept
	a.iUser = postgres.User
	return func() {}
}

func (a *dept) onEvent(*event.Data) {}

func (a *dept) Create(in *model.DeptCreateRequest) error {
	var (
		err error
	)
	if err = isExistParentId(in.ParentId); err != nil {
		return err
	}
	if err = isDuplicateDeptName(0, in.DeptName); err != nil {
		return err
	}
	c := buildDept(in)
	_, err = a.iDept.Create(c)
	return err
}

func (a *dept) Update(in *model.DeptUpdateRequest) error {
	var (
		dict = make(map[string]interface{})
		err  error
	)
	if in.ParentId == nil {
		return errors.ParameterErr.Error()
	}
	if err = isExistParentId(*in.ParentId); err != nil {
		return err
	}
	if err = isDuplicateDeptName(in.DeptId, in.DeptName); err != nil {
		return err
	}
	dict["sort"] = in.Sort
	dict["dept_name"] = in.DeptName
	dict["parent_id"] = in.ParentId
	return a.iDept.Update(in.DeptId, dict)
}

func (a *dept) Delete(in *model.DeptDeleteRequest) error {
	d, err := a.iDept.Find(in.ID)
	if err != nil {
		return err
	}
	if d.DeptId <= 0 {
		return errors.NoData.Error()
	}
	//顶层部门不能删除
	if d.ParentId == 0 {
		return errors.DeptConnotDel.Error()
	}
	existUser, err := a.iUser.CheckDeptExistUser(in.ID)
	if err != nil {
		log.Error("Delete.CheckDeptExistUser", err)
		return err
	}
	if existUser > 0 {
		return errors.DeptUseProhibitDel.Error()
	}
	_, err = a.iDept.FindByParameter(&model.DeptInfo{
		ParentId: in.ID,
	})
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		log.Error("Delete.FindByParameter", err)
		return err
	}
	if errors.Is(err, gorm.ErrRecordNotFound) {
		err = a.iDept.Delete(in.ID)
		if err != nil {
			return err
		}
	} else {
		log.WithFields(log.Fields{
			"id": in.ID,
		}).Error("删除部门单存在子部门")
		return errors.DeptExistSubDept.Error()
	}
	return nil
}

func (a *dept) List(in *model.DeptListRequest) (*model.DeptListResponse, error) {
	var (
		err   error
		total int
		list  []*entity.Dept
		out   = &model.DeptListResponse{}
	)

	if total, list, err = a.iDept.List(in); err != nil {
		return nil, err
	}

	out.Total = total
	out.Data = model.DeptsEntityToDto(list)

	return out, err
}

func (a *dept) GetDeptList(in *model.GetDeptListRequest) (*model.GetDeptListResponse, error) {
	var (
		err     error
		total   int
		out     = &model.GetDeptListResponse{}
		treeMap = make(map[int64][]*model.DeptInfo)
	)
	treeMap, err = getDeptTreeMap()
	if err != nil {
		log.Error("GetDeptList error", err)
		return nil, err
	}
	infoList := treeMap[0]
	for i := 0; i < len(infoList); i++ {
		err = getDeptChildrenList(infoList[i], treeMap)
	}
	out.Total = total
	out.Data = infoList
	return out, err
}

func (a *dept) GetDeptExclude(in *model.GetDeptExcludeRequest) (*model.GetDeptExcludeResponse, error) {
	var (
		err     error
		out     = &model.GetDeptExcludeResponse{}
		treeMap = make(map[int64][]*model.DeptInfo)
	)
	treeMap, err = getDeptTreeMap()
	if err != nil {
		log.Error("GetDeptList error", err)
		return nil, err
	}
	delete(treeMap, in.DeptId)
	if len(treeMap) > 0 {
		infoList := treeMap[0]
		for i := 0; i < len(infoList); i++ {
			err = getDeptChildrenList(infoList[i], treeMap)
		}
		out.Data = infoList
	}
	return out, err
}

func getDeptTreeMap() (map[int64][]*model.DeptInfo, error) {
	var (
		err      error
		deptList []*entity.Dept
		treeMap  = make(map[int64][]*model.DeptInfo)
		allDepts []*model.DeptInfo
	)
	deptList, err = Dept.iDept.GetBaseDeptTreeMap()
	if err != nil {
		log.Error("获取GetBaseDeptTreeMap失败!", err)
		return nil, err
	}
	allDepts = model.DeptsEntityToDto(deptList)
	treeMap = make(map[int64][]*model.DeptInfo)
	for _, v := range allDepts {
		treeMap[v.ParentId] = append(treeMap[v.ParentId], v)
	}
	return treeMap, err
}

func getDeptChildrenList(dept *model.DeptInfo, treeMap map[int64][]*model.DeptInfo) (err error) {
	dept.Children = treeMap[dept.DeptId]
	for i := 0; i < len(dept.Children); i++ {
		err = getDeptChildrenList(dept.Children[i], treeMap)
	}
	return err
}

// isDuplicateDeptName 验证是否重名
func isDuplicateDeptName(id int64, deptName string) error {
	err := Dept.iDept.IsExistDeptName(id, deptName)
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		return err
	}
	if !errors.Is(err, gorm.ErrRecordNotFound) {
		return errors.DeptExitsSameName.Error()
	}
	return nil
}

// isExistParentId  是否存在
func isExistParentId(parentId int64) error {
	if parentId <= 0 {
		return nil
	}
	d, err := Dept.iDept.Find(parentId)
	if err != nil {
		return err
	}
	if d.DeptId <= 0 {
		return errors.NoData.Error()
	}
	return nil
}

func buildDept(in *model.DeptCreateRequest) *entity.Dept {
	return &entity.Dept{
		DeptName: in.DeptName,

		ParentId: in.ParentId,

		Sort: in.Sort,

		CreatedAt: time.Now().Unix(),

		UpdatedAt: time.Now().Unix(),
	}
}
